/*
 * Copyright (c) 2005-2012 Imperas Software Ltd., www.imperas.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <stdio.h>
#include <string.h>

#include "icm/icmCpuManager.h"

#define SIM_ATTRS (ICM_ATTR_DEFAULT)

//
// Main routine
//
int main(int argc, char **argv) {

    // Check arguments for application to load
    if(argc!=2) {
        // incorrect arguments
        icmPrintf("Usage : %s <application name>\n", argv[0]);
        return -1;
    }
    const char *appName = argv[1];

    // initialize OVPsim, enabling verbose mode to get statistics at end
    // of execution
    icmInit(ICM_VERBOSE|ICM_STOP_ON_CTRLC, 0, 0);

    const char *v850Model    = icmGetVlnvString(NULL, "renesas.ovpworld.org", "processor", "v850", "1.0", "model");
    const char *v850Semihost = icmGetVlnvString(NULL, "renesas.ovpworld.org", "semihosting", "v850Newlib", "1.0", "model");
	
	// create the processor bus
    icmBusP bus = icmNewBus("busMain", 32);
	
	////////////////////////////////////////////////////////////////////////////
    // Memory
    ////////////////////////////////////////////////////////////////////////////

    // create two memory regions mapping all memory except the DMAC registers
    icmMemoryP mem1 = icmNewMemory("mem1", ICM_PRIV_RWX, 0x3fffffff);
    icmMemoryP mem2 = icmNewMemory("mem2", ICM_PRIV_RWX, 0x7fffffff);

    // connect memories to the bus
    icmConnectMemoryToBus(bus, "sp", mem1, 0xc0000000);
    icmConnectMemoryToBus(bus, "sp", mem2, 0x00000000);
    
	// create a processor instance
    icmProcessorP processor = icmNewProcessor(
        "CPU1",             // CPU name
        "v850",             // CPU type
        0,                  // CPU cpuId
        0,                  // CPU model flags
        32,                 // address bits
        v850Model,          // model file
        "modelAttrs",       // morpher attributes
        SIM_ATTRS,          // attributes
        0,                  // user-defined attributes
        v850Semihost,       // semi-hosting file
        "modelAttrs"        // semi-hosting attributes
    );

	// connect the processor instruction and data busses to the bus
    icmConnectProcessorBusses(processor, bus, bus);
	
    // load the application executable file into processor memory space
    if(!icmLoadProcessorMemory(processor, appName, False, False, True)) {
        return -1;
    }
	
	////////////////////////////////////////////////////////////////////////////
    // BYTEREAD Peripheral
    ////////////////////////////////////////////////////////////////////////////

    // instantiate the peripheral
    icmPseP byteRead = icmNewPSE("byteRead", "peripheral/pse.pse", NULL, NULL, NULL);

    // connect the BYTEREAD slave port on the bus and define the address range it occupies
    icmConnectPSEBus(byteRead, bus, "BYTEREADCSP", False, 0x80000000, 0x80000008);

    // simulate the platform
    icmProcessorP final = icmSimulatePlatform();

    // was simulation interrupted or did it complete
    if(final && (icmGetStopReason(final)==ICM_SR_INTERRUPT)) {
        icmPrintf("*** simulation interrupted\n");
    }

    icmTerminate();

    return 0;
}
